package com.ruijie.camerax.media;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;

import androidx.annotation.NonNull;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * author: luqihua
 * date:2019-11-06
 * description: 解码器
 **/
public class VideoDecoder extends MediaCodec.Callback {
    private static final String TAG = "VideoDecoder";
    private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;

    private MediaCodec mMediaCodec;

    private MediaFormat mMediaFormat;

    private Surface mOutSurface;

    private VideoEncoder mEncoder;

    private boolean isStart;
    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler;

    public void init(Surface surface, int width, int height, int orientation) throws IOException {
        this.mOutSurface = surface;
        mMediaFormat = MediaFormatCreate.createFormat(MIME_TYPE, width, height, orientation, false);
        //配置编码参数
        mMediaCodec = MediaCodec.createDecoderByType(MIME_TYPE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            startBackgroundThread();
            mMediaCodec.setCallback(this, mBackgroundHandler);
        } else {
            mMediaCodec.setCallback(this);
        }
        mMediaCodec.configure(mMediaFormat, mOutSurface, null, 0);
    }


    @Override
    public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
        StreamLog.d(TAG, "onInputBufferAvailable: h264-frame-size = " + mEncoder.available());
        if (!isStart) return;
        ByteBuffer byteBuffer = codec.getInputBuffer(index);
        if (byteBuffer == null) return;
        byteBuffer.clear();
        if (mEncoder != null) {
            VideoFrame videoFrame = mEncoder.pollH264Data();
            if (videoFrame != null) {
                byteBuffer.put(videoFrame.frameBytes);
                codec.queueInputBuffer(index, videoFrame.offset, videoFrame.size, videoFrame.presentationTimeUs, videoFrame.flags);
                return;
            }
        }
        codec.queueInputBuffer(index, 0, byteBuffer.position(), 0, 0);
    }

    @Override
    public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo bufferInfo) {
        StreamLog.d(TAG, "onOutputBufferAvailable: ");
        if (!isStart) return;
        if (mOutSurface == null) {
            ByteBuffer outputBuffer = codec.getOutputBuffer(index);
            MediaFormat outputFormat = codec.getOutputFormat(index);
            if (mMediaFormat == outputFormat && outputBuffer != null && bufferInfo.size > 0) {
                byte[] buffer = new byte[outputBuffer.remaining()];
                outputBuffer.get(buffer);
//                 TODO: 2019-11-11  解码后的yuv数据流在buffer中
            }
            mMediaCodec.releaseOutputBuffer(index, false);
        } else {
            mMediaCodec.releaseOutputBuffer(index, true);
        }
    }

    @Override
    public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
        Log.e(TAG, "onError:  ", e);
    }

    @Override
    public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {
        mMediaFormat = format;
    }


    public void setEncoder(VideoEncoder mEncoder) {
        this.mEncoder = mEncoder;
    }

    public void start() {
        //第二个参数是解码的时候用的
        if (isStart) return;
        mMediaCodec.start();
        Log.d(TAG, "start success");
        isStart = true;
    }


    public void stop() {
        isStart = false;
    }

    public void release() {
        try {
            if (mMediaCodec != null) {
                isStart = false;
                mMediaCodec.stop();
                mMediaCodec.release();
                mMediaCodec = null;
            }
            stopBackgroundThread();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * Starts a background thread and its {@link Handler}.
     */
    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    /**
     * Stops the background thread and its {@link Handler}.
     */
    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
